package com.grgbanking.encryp.util;

import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;

public class SmUtil {

    /**
     * sm3加密
     * @param hexStr  待加密的16进制字符串
     * @return  sm3的摘要
     */
    public static String sm3(String hexStr){

        Digest digest = new SM3Digest();
        byte[] data = Hex.decode(hexStr);
        byte[] digest1 = new byte[digest.getDigestSize()];

        digest.update(data, 0, data.length);
        digest.doFinal(digest1, 0);

        // 转换为16进制字符串
        String sm3Hex = HexUtil.encodeHexStr(digest1);
        return sm3Hex.toUpperCase();
    }

    /**
     * sm4 ecb方式加密， 参数与返回都16进制表示字符串
     * @param keyHexStr  key
     * @param dataHexStr 待加密H内容
     * @return  加密后内容
     * @throws Exception
     */
    public static String encryptSM4_ECB(String keyHexStr, String dataHexStr) throws Exception {

        byte[] data = HexUtil.decodeHex(dataHexStr);
        byte[] key = HexUtil.decodeHex(keyHexStr);

        SM4Engine engine = new SM4Engine();
        BufferedBlockCipher cipher = new BufferedBlockCipher(engine);
        cipher.init(true, new KeyParameter(key));

        byte[] out = new byte[data.length];
        cipher.processBytes(data, 0, data.length, out, 0);

        return HexUtil.encodeHexStr(out).toUpperCase();
    }

    /**
     * sm4 ecb方式解密， 参数与返回都16进制表示字符串
     * @param keyHexStr
     * @param dataHexStr
     * @return  解密后内容
     * @throws Exception
     */
    public static String decryptSM4_ECB(String keyHexStr, String dataHexStr) throws Exception {

        byte[] data = HexUtil.decodeHex(dataHexStr);
        byte[] key = HexUtil.decodeHex(keyHexStr);

        SM4Engine engine = new SM4Engine();
        BufferedBlockCipher cipher = new BufferedBlockCipher(engine);
        cipher.init(false, new KeyParameter(key)); //惟一不同， 在解密时，false初始化， 加密时，true初始化

        byte[] out = new byte[data.length];
        cipher.processBytes(data, 0, data.length, out, 0);

        return HexUtil.encodeHexStr(out).toUpperCase();
    }

    /**
     * sm3拼接后，再做sm3加密，
     * @param hexStr1
     * @param hexStr2
     * @return 返回16进制表示的摘要
     */
    public static String getSm3Sb(String hexStr1,String hexStr2){

        byte[] sm3SbBytes = HexUtil.decodeHex(hexStr1);
        byte[] bytes = HexUtil.decodeHex(hexStr2);
        for(int k=0;k<sm3SbBytes.length;k++){
            sm3SbBytes[k] += bytes[k];
        }
        String sm3Sb = HexUtil.encodeHexStr(sm3SbBytes);
        return sm3Sb;
    }

    /**
     * Sm2加密, 所有参数数据必须是16进制表示的字符串,  加密可以不要私钥，
     * @param paramHexStr
     * @param publicKey     公钥
     * @return
     * @throws Exception
     */
    public static String sm2Encrypt(String paramHexStr, String publicKey) throws Exception {
        if (!publicKey.startsWith("04") && publicKey.length() == 128){
            publicKey = "04" + publicKey; //BC库生成的公钥前面包含有04标志位,
        }
        SM2 sm2 = new SM2(null, publicKey);  //转字节Hex.decode(pubileKey) 传入也 ok
        byte[] byteArray = HexUtil.decodeHex(paramHexStr.toCharArray());
        return sm2.encryptHex(byteArray, KeyType.PublicKey).toUpperCase();
    }

    /**
     * Sm2解密  全部参数是  16进制表示的字符串，  解密必须传入私钥
     * @param paramStr      Hex数据
     * @param privateKeyHexStr      私钥
     * @return
     * @throws Exception
     */
    public static String sm2Decrypt(String paramStr, String privateKeyHexStr) throws Exception {
        if (!paramStr.startsWith("04")){
            paramStr = "04" + paramStr; //BC库生成的加密数据，解密的时候也需要有标志位04
        }
        SM2 sm2 = new SM2(privateKeyHexStr, null);
        byte[] byteArray = HexUtil.decodeHex(paramStr);
        byte decByte[] = sm2.decrypt(byteArray, KeyType.PrivateKey);
        return HexUtil.encodeHexStr(decByte).toUpperCase();
    }

}

